<template>
  <div class="msg" v-title data-title="私信">
    <div class="msg-header">
      <n-icon :size="22" @click="backMessage()">
        <chevron-back-outline></chevron-back-outline>
      </n-icon>
      <p calss="name">{{ targetUser.name }}</p>
      <span></span>
    </div>
    <div ref="msgBox" class="msg-main" @scroll="lazyLoading">
      <div class="content-box" v-for="(item, index) in msgDetails" :key="index">
        <!--自己发送的-->
        <div v-if="item.from_id == userInfo.uid">
          <common-avatar class="avatar-right" :url="userInfo.avatar" :size="45"></common-avatar>
          <span class="content-right">{{ item.content }}</span>
        </div>
        <!--收到的-->
        <div v-else>
          <common-avatar class="avatar-left" :url="targetUser.avatar" :size="45"></common-avatar>
          <div class="content-left-box">
            <span class="content-left">{{ item.content }}</span>
          </div>
        </div>
        <!-- 解决div无法撑开的问题 -->
        <div style="clear:both;"/>
      </div>
    </div>

    <div class="msg-input">
      <n-input v-model:value="msgForm.content" placeholder="发个消息呗~" maxlength="255" show-count
               @keydown.enter="sendMsg"></n-input>
      <n-button type="primary" :loading="sendLoading" @click="sendMsg">发送</n-button>
    </div>
  </div>
</template>

<script lang="ts">
import {Base64} from 'js-base64';
import storage from '@/utils/stored-data';
import {getAccessToken} from "@/api/token";
import {MsgSocketURL} from '@/utils/request';
import {useRoute, useRouter} from 'vue-router';
import {getMsgDetailsAPI, sendMsgAPI} from '@/api/message';
import CommonAvatar from '@/components/CommonAvatar.vue';
import {NInput, NIcon, NButton, useMessage} from 'naive-ui';
import {messageDetailsType} from '@/types/message';
import {ChevronBackOutline} from '@vicons/ionicons5';
import {onBeforeMount, onBeforeUnmount, reactive, ref, computed, nextTick, defineComponent} from 'vue';

export default defineComponent({
  setup() {
    const msgDetails = ref<Array<messageDetailsType>>([]);
    const msgForm = reactive({
      fid: 0,
      content: ''
    })

    const message = useMessage();//通知
    //用户信息
    const userInfo = computed(() => {
      return storage.get("userInfo");
    })

    //取消息详情
    const page = ref(1);
    const loading = ref(false);
    const noMore = ref(false);//没有更多
    const allowToBottom = ref(true);//是否允许自动跳转到底部
    const targetUser = reactive({
      name: "",
      avatar: ""
    })

    //获取更多消息
    const getMsgContent = (fid: number) => {
      loading.value = true;
      getMsgDetailsAPI(fid, page.value, 10).then((res) => {
        if (res.data.code === 2000) {
          const resMsg = res.data.data.messages;
          if (resMsg.length < 10) {
            noMore.value = true;
          }
          msgDetails.value = resMsg.concat(msgDetails.value);
          nextTick(() => {
            toBottom()
          })
        }
        loading.value = false;
      });
    }

    //加载更多
    const msgBox = ref<HTMLElement | null>(null);
    const lazyLoading = () => {
      const scrollTop = msgBox.value?.scrollTop || Infinity;
      if (scrollTop < 30 && !loading.value && !noMore.value) {
        page.value++;
        allowToBottom.value = false;
        getMsgContent(msgForm.fid);
      }
    }

    //到达底部
    const toBottom = () => {
      if (allowToBottom.value) {
        msgBox.value!.scrollTop = msgBox.value!.scrollHeight;
      } else {
        msgBox.value!.scrollTop = 160;
        allowToBottom.value = true;
      }
    }

    const router = useRouter();
    const backMessage = () => {
      // router.push({ name: 'Home'});
      router.push({name: "Announce"});
    }

    //发送消息
    const sendLoading = ref(false);
    const sendMsg = () => {
      if (!msgForm.content) {
        message.error('不能发送空消息');
        return;
      }
      sendLoading.value = true;
      sendMsgAPI(msgForm).then((res) => {
        if (res.data.code === 2000) {
          msgDetails.value.push({
            fid: 0,
            from_id: userInfo.value.uid,
            content: msgForm.content,
            created_at: ""
          });
          msgForm.content = "";
          sendLoading.value = false;
          nextTick(() => {
            toBottom()
          })
        }
      }).catch(() => {
        sendLoading.value = false;
        message.error('发送失败');
      });
    }

    //websocket
    const SocketURL = ref("");
    const websocket = ref<WebSocket | null>(null);

    const initWebSocket = () => {
      const wsProtocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
      if (MsgSocketURL === "/api/v1/message/ws") {
        SocketURL.value = wsProtocol + window.location.host + "/api/v1/message/ws";
      } else {
        //处理协议部分
        let reg = new RegExp('^http(s)?:')
        SocketURL.value = MsgSocketURL.replace(reg, wsProtocol);
      }
      SocketURL.value += "?token=" + storage.get("access_token");
      websocket.value = new WebSocket(SocketURL.value);
      websocket.value.onmessage = websocketOnmessage;
    }

    //数据接收
    const websocketOnmessage = (e: any) => {
      const res = JSON.parse(Base64.decode(e.data));
      if (msgForm.fid === res.fid) {
        msgDetails.value.push({
          fid: msgForm.fid,
          from_id: res.fid,
          content: res.content,
          created_at: ""
        });
        nextTick(() => {
          toBottom()
        })
      }
    }

    // 刷新token并建立websocket连接
    const refreshToken = () => {
      getAccessToken().then((res) => {
        if (res.data.code === 2000) {
          storage.set("access_token", res.data.data.token, 5);
          initWebSocket();
        }
      })
    }

    //加载和卸载页面
    const route = useRoute();
    onBeforeMount(() => {
      if (route.query.fid) {
        msgForm.fid = Number(route.query.fid);
        targetUser.name = (route.query.name || "").toString();
        targetUser.avatar = (route.query.avatar || "").toString();
      }
      getMsgContent(msgForm.fid);
      //如果没有token则不建立websocket
      refreshToken();
    })

    onBeforeUnmount(() => {
      if (websocket.value) {
        websocket.value.close();
      }
    })

    return {
      msgBox,
      userInfo,
      msgDetails,
      targetUser,
      msgForm,
      sendLoading,
      backMessage,
      sendMsg,
      lazyLoading,
      getMsgContent
    }
  },
  components: {
    NIcon,
    NInput,
    NButton,
    CommonAvatar,
    ChevronBackOutline
  }
});
</script>

<style lang="less" scoped>
.msg {

  .msg-header {
    position: fixed;
    height: 50px;
    width: 100%;
    z-index: 999;
    background: #fff;
    display: flex;
    align-items: center;
    justify-content: space-between;

    span {
      width: 50px;
      text-align: center;
    }
  }

  .msg-main {
    padding-top: 50px;
    height: calc(100vh - 100px);
    background-color: #f7f7f7;
    border-bottom: 1px solid #e1e2e3;
    overflow-y: auto;

    /**修改滚动条样式 */

    &::-webkit-scrollbar {
      width: 8px;
    }

    &::-webkit-scrollbar-thumb {
      /*滚动条里面小方块*/
      border-radius: 2px;
      background: #999999;
    }

    &::-webkit-scrollbar-track {
      /*滚动条里面轨道*/
      border-radius: 5px;
    }
  }

  /**聊天部分 */

  .content-box {
    min-height: 70px;
    margin: 6px 20px;

    &:nth-child(1) {
      margin-top: 10px;
    }

    .avatar-right {
      float: right;
    }

    .content-right {
      float: right;
      max-width: 80%;
      margin-right: 10px;
      margin-top: 6px;
      background-color: #40a9ff;
      color: #fff;
      font-size: 16px;
      border-radius: 3px;
      padding: 5px 10px 5px 10px;
    }

    .avatar-left {
      float: left;
    }

    .content-left-box {
      float: left;
      margin-left: 10px;
      margin-top: 10px;
      max-width: 80%;
      background: #fff;
      padding: 5px 10px 5px 10px;
      border-radius: 3px;
    }

    .content-left {
      font-size: 1rem;
    }
  }

  .msg-input {
    height: 50px;
    display: flex;
    padding: 0 6px;
    align-items: center;
    justify-content: space-between;

    button {
      width: 80px;
    }
  }
}
</style>